/// <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>
        /// 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);
        }
Ejemplo n.º 3
0
        /// <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);
        }
Ejemplo n.º 4
0
        /// <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);
        }
Ejemplo n.º 5
0
        /// <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);
        }
Ejemplo n.º 6
0
 /// <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);
 }
Ejemplo n.º 7
0
        /// <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);
        }
Ejemplo n.º 8
0
        /// <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);
        }
Ejemplo n.º 9
0
        /// <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);
        }
Ejemplo n.º 10
0
        /// <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);
        }
Ejemplo n.º 11
0
        /// <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);

            // Retrieve register context
            context.SetInstruction(CPUx86.Instruction.MovInstruction, new RegisterOperand(u4, GeneralPurposeRegister.EAX), new MemoryOperand(u4, GeneralPurposeRegister.ESP, new IntPtr(28)));

            // Restore registers (Note: EAX and EDX are NOT restored!)
            context.AppendInstruction(CPUx86.Instruction.MovInstruction, new RegisterOperand(u4, GeneralPurposeRegister.EDX), new MemoryOperand(u4, GeneralPurposeRegister.EAX, new IntPtr(28)));
            context.AppendInstruction(CPUx86.Instruction.MovInstruction, new RegisterOperand(u4, GeneralPurposeRegister.EBX), new MemoryOperand(u4, GeneralPurposeRegister.EAX, new IntPtr(4)));
            context.AppendInstruction(CPUx86.Instruction.MovInstruction, new RegisterOperand(u4, GeneralPurposeRegister.EDI), new MemoryOperand(u4, GeneralPurposeRegister.EAX, new IntPtr(20)));
            context.AppendInstruction(CPUx86.Instruction.MovInstruction, new RegisterOperand(u4, GeneralPurposeRegister.ESI), new MemoryOperand(u4, GeneralPurposeRegister.EAX, new IntPtr(16)));
            context.AppendInstruction(CPUx86.Instruction.MovInstruction, new RegisterOperand(u4, GeneralPurposeRegister.ESP), new MemoryOperand(u4, GeneralPurposeRegister.EAX, new IntPtr(32)));
            context.AppendInstruction(CPUx86.Instruction.MovInstruction, new RegisterOperand(u4, GeneralPurposeRegister.EBP), new MemoryOperand(u4, GeneralPurposeRegister.EAX, new IntPtr(24)));

            // Jmp to EIP (stored in EDX)
            context.AppendInstruction(CPUx86.Instruction.JmpInstruction);
            context.SetOperand(0, new RegisterOperand(u4, GeneralPurposeRegister.EDX));
        }
Ejemplo n.º 12
0
        /// <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();

            int irq = -1;

            object obj = (context.Operand1 as ConstantOperand).Value;

            if ((obj is int) || (obj is uint))
                irq = (int)obj;
            else if (obj is sbyte)
                irq = (sbyte)obj;

            if ((irq > 256) || (irq < 0))
                throw new InvalidOperationException();

            SigType PTR = new SigType(CilElementType.Ptr);

            context.SetInstruction(IR.Instruction.MoveInstruction, context.Result, new SymbolOperand(PTR, @"Mosa.Tools.Compiler.LinkerGenerated.<$>InterruptISR" + irq.ToString() + "()"));
        }
Ejemplo n.º 13
0
        /// <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);
        }
Ejemplo n.º 14
0
        /// <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);
        }
Ejemplo n.º 15
0
        /// <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)
        {
            Context loadContext = new Context(context.InstructionSet, context.Operand1.Definitions[0]);
            ConstantOperand op1 = loadContext.Operand1 as ConstantOperand;

            if (op1 == null)
                throw new InvalidOperationException();

            int irq = -1;

            object obj = op1.Value;

            if ((obj is int) || (obj is uint))
                irq = (int)obj;
            else if (obj is sbyte)
                irq = (sbyte)obj;

            if ((irq > 256) || (irq < 0))
                throw new InvalidOperationException();

            SigType PTR = new SigType(CilElementType.Ptr);

            context.SetInstruction(IR.Instruction.MoveInstruction, context.Result, new SymbolOperand(PTR, @"Mosa.Tools.Compiler.LinkerGenerated.<$>InterruptISR" + irq.ToString() + "()"));
        }
        /// <summary>
        /// Expands the unary branch instruction for 64-bits.
        /// </summary>
        /// <param name="context">The context.</param>
        private void ExpandUnaryBranch(Context context)
        {
            Debug.Assert(context.Branch.Targets.Length == 2);

            int target = context.Branch.Targets[0];

            Operand op1H, op1L, op2H, op2L;
            Operand zero = new ConstantOperand(new SigType(CilElementType.I4), (int)0);
            SplitLongOperand(context.Operand1, out op1L, out op1H);
            SplitLongOperand(zero, out op2L, out op2H);
            IR.ConditionCode code;

            switch (((context.Instruction) as CIL.ICILInstruction).OpCode)
            {
                // Signed
                case CIL.OpCode.Brtrue: code = IR.ConditionCode.NotEqual; break;
                case CIL.OpCode.Brfalse: code = IR.ConditionCode.Equal; break;
                case CIL.OpCode.Beq_s: code = IR.ConditionCode.Equal; break;
                case CIL.OpCode.Bge_s: code = IR.ConditionCode.GreaterOrEqual; break;
                case CIL.OpCode.Bgt_s: code = IR.ConditionCode.GreaterThan; break;
                case CIL.OpCode.Ble_s: code = IR.ConditionCode.LessOrEqual; break;
                case CIL.OpCode.Blt_s: code = IR.ConditionCode.LessThan; break;

                // Unsigned
                case CIL.OpCode.Bne_un_s: code = IR.ConditionCode.NotEqual; break;
                case CIL.OpCode.Bge_un_s: code = IR.ConditionCode.UnsignedGreaterOrEqual; break;
                case CIL.OpCode.Bgt_un_s: code = IR.ConditionCode.UnsignedGreaterThan; break;
                case CIL.OpCode.Ble_un_s: code = IR.ConditionCode.UnsignedLessOrEqual; break;
                case CIL.OpCode.Blt_un_s: code = IR.ConditionCode.UnsignedLessThan; break;

                // Long form signed
                case CIL.OpCode.Beq: goto case CIL.OpCode.Beq_s;
                case CIL.OpCode.Bge: goto case CIL.OpCode.Bge_s;
                case CIL.OpCode.Bgt: goto case CIL.OpCode.Bgt_s;
                case CIL.OpCode.Ble: goto case CIL.OpCode.Ble_s;
                case CIL.OpCode.Blt: goto case CIL.OpCode.Blt_s;

                // Long form unsigned
                case CIL.OpCode.Bne_un: goto case CIL.OpCode.Bne_un_s;
                case CIL.OpCode.Bge_un: goto case CIL.OpCode.Bge_un_s;
                case CIL.OpCode.Bgt_un: goto case CIL.OpCode.Bgt_un_s;
                case CIL.OpCode.Ble_un: goto case CIL.OpCode.Ble_un_s;
                case CIL.OpCode.Blt_un: goto case CIL.OpCode.Blt_un_s;
                default: throw new NotImplementedException();
            }

            //UNUSED:
            //IR.ConditionCode conditionHigh = GetHighCondition(code);

            Context[] newBlocks = CreateEmptyBlockContexts(context.Label, 3);
            Context nextBlock = SplitContext(context, false);

            context.SetInstruction(CPUx86.Instruction.JmpInstruction, newBlocks[0].BasicBlock);
            LinkBlocks(context, newBlocks[0]);
            // Compare high dwords
            newBlocks[0].AppendInstruction(CPUx86.Instruction.DirectCompareInstruction, op1H, op2H);
            // Branch if check already gave results
            newBlocks[0].AppendInstruction(CPUx86.Instruction.BranchInstruction, IR.ConditionCode.Equal, newBlocks[2].BasicBlock);
            newBlocks[0].AppendInstruction(CPUx86.Instruction.JmpInstruction, newBlocks[1].BasicBlock);
            LinkBlocks(newBlocks[0], newBlocks[1], newBlocks[2]);

            newBlocks[1].AppendInstruction(CPUx86.Instruction.BranchInstruction, code, FindBlock(target));
            //            newBlocks[1].SetBranch(target);
            newBlocks[1].AppendInstruction(CPUx86.Instruction.JmpInstruction);
            newBlocks[1].SetBranch(nextBlock.BasicBlock);
            LinkBlocks(newBlocks[1], FindBlock(target));
            LinkBlocks(newBlocks[1], nextBlock);

            // Compare low dwords
            newBlocks[2].SetInstruction(CPUx86.Instruction.DirectCompareInstruction, op1L, op2L);
            // Set the unsigned result...
            newBlocks[2].AppendInstruction(CPUx86.Instruction.BranchInstruction, code, FindBlock(target));
            //            newBlocks[1].SetBranch(target);
            newBlocks[2].AppendInstruction(CPUx86.Instruction.JmpInstruction);
            newBlocks[2].SetBranch(nextBlock.BasicBlock);
            LinkBlocks(newBlocks[2], FindBlock(target));
            LinkBlocks(newBlocks[2], nextBlock);
        }
        /// <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 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);
        }
        /// <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 neg instruction for 64-bits.
        /// </summary>
        /// <param name="context">The context.</param>
        private void ExpandXor(Context context)
        {
            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);

            context.SetInstruction(CPUx86.Instruction.MovInstruction, op0H, op1H);
            context.AppendInstruction(CPUx86.Instruction.MovInstruction, op0L, op1L);
            context.AppendInstruction(CPUx86.Instruction.XorInstruction, op0H, op2H);
            context.AppendInstruction(CPUx86.Instruction.XorInstruction, op0L, op2L);
        }
        /// <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>
        /// Expands the move instruction for 64-bits.
        /// </summary>
        /// <param name="context">The context.</param>
        private void ExpandMove(Context context)
        {
            Operand op0L, op0H, op1L, op1H;

            if (context.Result.StackType == StackTypeCode.Int64)
            {
                SplitLongOperand(context.Result, out op0L, out op0H);
                SplitLongOperand(context.Operand1, out op1L, out op1H);

                context.SetInstruction(CPUx86.Instruction.MovInstruction, op0L, op1L);
                context.AppendInstruction(CPUx86.Instruction.MovInstruction, op0H, op1H);
            }
            else
            {
                SplitLongOperand(context.Operand1, out op1L, out op1H);
                context.SetInstruction(CPUx86.Instruction.MovInstruction, context.Result, op1L);
            }
        }
        /// <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 div.
        /// </summary>
        /// <param name="context">The context.</param>
        private void ExpandDiv(Context context)
        {
            SigType I4 = new SigType(CilElementType.I4);
            SigType U4 = new SigType(CilElementType.U4);
            SigType U1 = new SigType(CilElementType.U1);

            Operand op0H, op1H, op2H, op0L, op1L, op2L;
            //Operand op1 = EmitConstant(context.Operand1);
            //Operand op2 = EmitConstant(context.Operand2);
            SplitLongOperand(context.Result, out op0L, out op0H);
            SplitLongOperand(context.Operand1, out op1L, out op1H);
            SplitLongOperand(context.Operand2, out op2L, out op2H);

            Context[] newBlocks = CreateEmptyBlockContexts(context.Label, 17);
            Context nextBlock = SplitContext(context, false);

            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);

            RegisterOperand ueax = new RegisterOperand(U4, GeneralPurposeRegister.EAX);
            RegisterOperand uedx = new RegisterOperand(U4, GeneralPurposeRegister.EDX);
            RegisterOperand uecx = new RegisterOperand(U4, GeneralPurposeRegister.ECX);
            //UNUSED:
            //RegisterOperand uebx = new RegisterOperand(U4, GeneralPurposeRegister.EBX);
            //RegisterOperand uedi = new RegisterOperand(U4, GeneralPurposeRegister.EDI);
            //RegisterOperand uesi = new RegisterOperand(U4, GeneralPurposeRegister.ESI);

            // ; 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
            // 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);
            LinkBlocks(context, newBlocks[0]);
            newBlocks[0].SetInstruction(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[1], newBlocks[2]);

            newBlocks[1].SetInstruction(CPUx86.Instruction.IncInstruction, edi);
            newBlocks[1].AppendInstruction(CPUx86.Instruction.MovInstruction, uedx, 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, uedx);
            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
            // inc     edi             ; complement the result sign flag
            // mov     edx,LOWORD(DVSR) ; lo word of a
            // neg     eax             ; make b positive
            // neg     edx
            // sbb     eax,0
            // mov     HIWORD(DVSR),eax ; save positive value
            // mov     LOWORD(DVSR),edx
            newBlocks[2].SetInstruction(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[3], newBlocks[4]);

            newBlocks[3].SetInstruction(CPUx86.Instruction.IncInstruction, edi);
            newBlocks[3].AppendInstruction(CPUx86.Instruction.MovInstruction, uedx, 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, uedx);
            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     ebx,eax         ; save high 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].SetInstruction(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[5], newBlocks[6]);

            newBlocks[5].SetInstruction(CPUx86.Instruction.MovInstruction, uecx, 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, ebx, eax);
            newBlocks[5].AppendInstruction(CPUx86.Instruction.MovInstruction, ueax, op1L);
            newBlocks[5].AppendInstruction(CPUx86.Instruction.DirectDivisionInstruction, eax, ecx);
            newBlocks[5].AppendInstruction(CPUx86.Instruction.MovInstruction, edx, ebx);
            newBlocks[5].AppendInstruction(CPUx86.Instruction.JmpInstruction, newBlocks[14].BasicBlock);
            LinkBlocks(newBlocks[5], newBlocks[14]);

            // 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].SetInstruction(CPUx86.Instruction.MovInstruction, ebx, eax);
            newBlocks[6].AppendInstruction(CPUx86.Instruction.MovInstruction, uecx, op2L);
            newBlocks[6].AppendInstruction(CPUx86.Instruction.MovInstruction, edx, op1H);
            newBlocks[6].AppendInstruction(CPUx86.Instruction.MovInstruction, ueax, 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
            // mov     esi,eax         ; save quotient
            //
            //

            // ;
            // ; 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.
            // ;

            // mul     dword ptr HIWORD(DVSR) ; QUOT * HIWORD(DVSR)
            // mov     ecx,eax
            // mov     eax,LOWORD(DVSR)
            // mul     esi             ; QUOT * LOWORD(DVSR)
            // add     edx,ecx         ; EDX:EAX = QUOT * DVSR
            // jc      short L6        ; carry means Quotient is off by 1
            newBlocks[7].SetInstruction(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].SetInstruction(CPUx86.Instruction.DirectDivisionInstruction, eax, ecx);
            newBlocks[8].AppendInstruction(CPUx86.Instruction.MovInstruction, esi, eax);
            newBlocks[8].AppendInstruction(CPUx86.Instruction.MulInstruction, null, op2H);
            newBlocks[8].AppendInstruction(CPUx86.Instruction.MovInstruction, ecx, eax);
            newBlocks[8].AppendInstruction(CPUx86.Instruction.MovInstruction, ueax, op2L);
            newBlocks[8].AppendInstruction(CPUx86.Instruction.MulInstruction, null, esi);
            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[9], newBlocks[12]);

            newBlocks[9].SetInstruction(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[10], newBlocks[12]);

            newBlocks[10].SetInstruction(CPUx86.Instruction.BranchInstruction, IR.ConditionCode.UnsignedLessThan, newBlocks[13].BasicBlock);
            newBlocks[10].AppendInstruction(CPUx86.Instruction.JmpInstruction, newBlocks[11].BasicBlock);
            LinkBlocks(newBlocks[10], newBlocks[11], newBlocks[13]);

            newBlocks[11].SetInstruction(CPUx86.Instruction.DirectCompareInstruction, ueax, 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[12], newBlocks[13]);

            // L6:
            newBlocks[12].SetInstruction(CPUx86.Instruction.DecInstruction, esi);
            newBlocks[12].AppendInstruction(CPUx86.Instruction.JmpInstruction, newBlocks[13].BasicBlock);
            LinkBlocks(newBlocks[12], newBlocks[13]);

            // L7:
            newBlocks[13].SetInstruction(CPUx86.Instruction.XorInstruction, edx, edx);
            newBlocks[13].AppendInstruction(CPUx86.Instruction.MovInstruction, eax, esi);
            newBlocks[13].AppendInstruction(CPUx86.Instruction.JmpInstruction, newBlocks[14].BasicBlock);
            LinkBlocks(newBlocks[13], newBlocks[14]);

            ;
            // ; Just the cleanup left to do.  edx:eax contains the quotient.  Set the sign
            // ; according to the save value, cleanup the stack, and return.
            // ;
            // L4:
            //        dec     edi             ; check to see if result is negative
            //        jnz     short L8        ; if EDI == 0, result should be negative
            //        neg     edx             ; otherwise, negate the result
            //        neg     eax
            //        sbb     edx,0
            newBlocks[14].SetInstruction(CPUx86.Instruction.DecInstruction, edi);
            newBlocks[14].AppendInstruction(CPUx86.Instruction.BranchInstruction, IR.ConditionCode.NotEqual, newBlocks[16].BasicBlock);
            newBlocks[14].AppendInstruction(CPUx86.Instruction.JmpInstruction, newBlocks[15].BasicBlock);
            LinkBlocks(newBlocks[14], newBlocks[15], newBlocks[16]);

            newBlocks[15].SetInstruction(CPUx86.Instruction.NegInstruction, edx);
            newBlocks[15].AppendInstruction(CPUx86.Instruction.NegInstruction, eax);
            newBlocks[15].AppendInstruction(CPUx86.Instruction.SbbInstruction, edx, new ConstantOperand(I4, 0));
            newBlocks[15].AppendInstruction(CPUx86.Instruction.JmpInstruction, newBlocks[16].BasicBlock);
            LinkBlocks(newBlocks[15], newBlocks[16]);

            newBlocks[16].SetInstruction(CPUx86.Instruction.MovInstruction, op0L, ueax);
            newBlocks[16].AppendInstruction(CPUx86.Instruction.MovInstruction, op0H, edx);
            newBlocks[16].AppendInstruction(CPUx86.Instruction.PopInstruction, ebx);
            newBlocks[16].AppendInstruction(CPUx86.Instruction.PopInstruction, esi);
            newBlocks[16].AppendInstruction(CPUx86.Instruction.PopInstruction, edi);
            newBlocks[15].AppendInstruction(CPUx86.Instruction.JmpInstruction, nextBlock.BasicBlock);
            LinkBlocks(newBlocks[16], nextBlock);
        }
Ejemplo n.º 26
0
        /// <summary>
        /// Eliminates the common subexpressions.
        /// </summary>
        /// <param name="ctx">The context.</param>
        private static void EliminateCommonSubexpressions(Context ctx)
        {
            List <AEBinExp> AEB = new List <AEBinExp> ();
            List <AEBinExp> tmp;

            AEBinExp aeb;

            for (; !ctx.EndOfInstruction; ctx.GotoNext())
            {
                IInstruction instruction = ctx.Instruction;
                // block.Instructions[i];
                RegisterOperand temp  = null;
                bool            found = false;

                if ((instruction is CIL.ArithmeticInstruction) && (instruction is CIL.BinaryInstruction))
                {
                    tmp = new List <AEBinExp> (AEB);

                    while (tmp.Count > 0)
                    {
                        aeb = tmp[0];
                        tmp.RemoveAt(0);

                        // Match current instruction's expression against those
                        // in AEB, including commutativity
                        if (IsCommutative(instruction))
                        {
                            //int position = aeb.Position;
                            found = true;

                            // If no variable in tuple, create a new temporary and
                            // insert an instruction evaluating the expression
                            // and assigning it to the temporary
                            if (aeb.Var == null)
                            {
                                // new_tmp()
                                AEB.Remove(aeb);
                                AEB.Add(new AEBinExp(aeb.Position, aeb.Operand1, aeb.Operator, aeb.Operand2, temp));

                                // Insert new assignment to instruction stream in block
                                Context inserted = ctx.InsertBefore();

                                switch (aeb.Operator)
                                {
                                case Operation.Add:
                                    inserted.SetInstruction(CIL.Instruction.Get(CIL.OpCode.Add), temp, aeb.Operand1, aeb.Operand2);
                                    break;

                                case Operation.Mul:
                                    inserted.SetInstruction(CIL.Instruction.Get(CIL.OpCode.Mul), temp, aeb.Operand1, aeb.Operand2);
                                    break;

                                case Operation.Or:
                                    inserted.SetInstruction(CIL.Instruction.Get(CIL.OpCode.Or), temp, aeb.Operand1, aeb.Operand2);
                                    break;

                                case Operation.Xor:
                                    inserted.SetInstruction(CIL.Instruction.Get(CIL.OpCode.Xor), temp, aeb.Operand1, aeb.Operand2);
                                    break;

                                default:
                                    break;
                                }

                                //block.Instructions.Insert(position, inst);

                                //++position;
                                //++i;

                                // Replace current instruction by one that copies
                                // the temporary instruction
                                // FIXME PG:
                                // block.Instructions[position] = new IR.MoveInstruction(block.Instructions[position].Results[0], temp);
                                // ctx.SetInstruction(IR.MoveInstruction); // FIXME PG
                                // ctx.Result = block.Instructions[position].Results[0]; // FIXME PG
                                ctx.Operand1 = temp;
                            }
                            else
                            {
                                temp = (RegisterOperand)aeb.Var;
                            }

                            // FIXME PG
                            // block.Instructions[i] = new IR.MoveInstruction(instruction.Results[0], temp);
                        }
                    }

                    if (!found)
                    {
                        Operation opr = Operation.None;

                        if (instruction is CIL.AddInstruction)
                        {
                            opr = Operation.Add;
                        }
                        else if (instruction is CIL.MulInstruction)
                        {
                            opr = Operation.Mul;
                        }
                        else if (instruction is IR.LogicalAndInstruction)
                        {
                            opr = Operation.And;
                        }
                        // Insert new tuple
                        AEB.Add(new AEBinExp(ctx.Index, ctx.Operand1, opr, ctx.Operand2, null));
                    }

                    // Remove all tuples that use the variable assigned to by
                    // the current instruction
                    tmp = new List <AEBinExp> (AEB);

                    while (tmp.Count > 0)
                    {
                        aeb = tmp[0];
                        tmp.RemoveAt(0);

                        if (ctx.Operand1 == aeb.Operand1 || ctx.Operand2 == aeb.Operand2)
                        {
                            AEB.Remove(aeb);
                        }
                    }
                }
            }
        }
        /// <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 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 not instruction for 64-bits.
        /// </summary>
        /// <param name="context">The context.</param>
        private void ExpandNot(Context context)
        {
            Operand op0H, op1H, op0L, op1L;
            SplitLongOperand(context.Result, out op0L, out op0H);
            SplitLongOperand(context.Operand1, out op1L, out op1H);

            context.SetInstruction(IR.Instruction.LogicalNotInstruction, op0H, op1H);
            context.AppendInstruction(IR.Instruction.LogicalNotInstruction, op0L, op1L);
        }
        /// <summary>
        /// Expands the binary comparison instruction for 64-bits.
        /// </summary>
        /// <param name="context">The context.</param>
        private void ExpandComparison(Context context)
        {
            Operand op0 = context.Result;
            Operand op1 = context.Operand1;
            Operand op2 = context.Operand2;

            Debug.Assert(op1 != null && op2 != null, @"IntegerCompareInstruction operand not memory!");
            Debug.Assert(op0 is MemoryOperand || op0 is RegisterOperand, @"IntegerCompareInstruction result not memory and not register!");

            SigType I4 = new SigType(CilElementType.I4);
            //UNUSED:
            //SigType U4 = new SigType(CilElementType.U4);

            Operand op1L, op1H, op2L, op2H;
            SplitLongOperand(op1, out op1L, out op1H);
            SplitLongOperand(op2, out op2L, out op2H);

            Context[] newBlocks = CreateEmptyBlockContexts(context.Label, 4);
            IR.ConditionCode conditionCode = context.ConditionCode;
            Context nextBlock = SplitContext(context, false);

            // Compare high dwords
            context.SetInstruction(CPUx86.Instruction.CmpInstruction, op1H, op2H);
            context.AppendInstruction(CPUx86.Instruction.BranchInstruction, IR.ConditionCode.Equal, newBlocks[1].BasicBlock);
            context.AppendInstruction(CPUx86.Instruction.JmpInstruction, newBlocks[0].BasicBlock);
            LinkBlocks(context, newBlocks[0], newBlocks[1]);

            // Branch if check already gave results
            newBlocks[0].SetInstruction(CPUx86.Instruction.BranchInstruction, conditionCode, newBlocks[2].BasicBlock);
            newBlocks[0].AppendInstruction(CPUx86.Instruction.JmpInstruction, newBlocks[3].BasicBlock);
            LinkBlocks(newBlocks[0], newBlocks[2], newBlocks[3]);

            // Compare low dwords
            newBlocks[1].SetInstruction(CPUx86.Instruction.CmpInstruction, op1L, op2L);
            // Set the unsigned result...
            newBlocks[1].AppendInstruction(CPUx86.Instruction.BranchInstruction, GetUnsignedConditionCode(conditionCode), newBlocks[2].BasicBlock);
            newBlocks[1].AppendInstruction(CPUx86.Instruction.JmpInstruction, newBlocks[3].BasicBlock);
            LinkBlocks(newBlocks[1], newBlocks[2], newBlocks[3]);

            // Success
            newBlocks[2].SetInstruction(CPUx86.Instruction.MovsxInstruction, op0, new ConstantOperand(I4, 1));
            newBlocks[2].AppendInstruction(CPUx86.Instruction.JmpInstruction, nextBlock.BasicBlock);
            LinkBlocks(newBlocks[2], nextBlock);

            // Failed
            newBlocks[3].SetInstruction(CPUx86.Instruction.MovsxInstruction, op0, new ConstantOperand(I4, 0));
            newBlocks[3].AppendInstruction(CPUx86.Instruction.JmpInstruction, nextBlock.BasicBlock);
            LinkBlocks(newBlocks[3], 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);
        }