/// <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); }
/// <summary> /// Replaces the instrinsic call site /// </summary> /// <param name="context">The context.</param> /// <param name="typeSystem">The type system.</param> public void ReplaceIntrinsicCall(Context context, ITypeSystem typeSystem) { Operand result = context.Result; RegisterOperand tmp = new RegisterOperand(new Mosa.Runtime.Metadata.Signatures.SigType(Mosa.Runtime.Metadata.CilElementType.Ptr), GeneralPurposeRegister.EDX); MemoryOperand operand = new MemoryOperand(context.Operand1.Type, GeneralPurposeRegister.EDX, new System.IntPtr(0)); context.SetInstruction(CPUx86.Instruction.MovInstruction, tmp, context.Operand1); context.AppendInstruction(CPUx86.Instruction.MovInstruction, result, operand); }
/// <summary> /// Replaces the instrinsic call site /// </summary> /// <param name="context">The context.</param> /// <param name="typeSystem">The type system.</param> public void ReplaceIntrinsicCall(Context context, ITypeSystem typeSystem) { SigType I4 = new SigType(CilElementType.I4); RegisterOperand esp = new RegisterOperand(I4, GeneralPurposeRegister.ESP); context.SetInstruction(CPUx86.Instruction.MovInstruction, esp, context.Operand1); context.AppendInstruction(CPUx86.Instruction.PopadInstruction); context.AppendInstruction(CPUx86.Instruction.AddInstruction, esp, new ConstantOperand(I4, 0x08)); context.AppendInstruction(CPUx86.Instruction.StiInstruction); context.AppendInstruction(CPUx86.Instruction.IRetdInstruction); }
/// <summary> /// Replaces the instrinsic call site /// </summary> /// <param name="context">The context.</param> public void ReplaceIntrinsicCall(Context context) { Operand operand1 = context.Operand1; Operand operand2 = context.Operand2; RegisterOperand edx = new RegisterOperand (operand1.Type, GeneralPurposeRegister.EDX); RegisterOperand eax = new RegisterOperand (operand2.Type, GeneralPurposeRegister.EAX); context.SetInstruction (CPUx86.Instruction.MovInstruction, edx, operand1); context.AppendInstruction (CPUx86.Instruction.MovInstruction, eax, operand2); context.AppendInstruction (CPUx86.Instruction.OutInstruction, null, edx, eax); }
/// <summary> /// Replaces the instrinsic call site /// </summary> /// <param name="context">The context.</param> public void ReplaceIntrinsicCall(Context context) { Operand result = context.Result; Operand operand = context.Operand1; RegisterOperand eax = new RegisterOperand(new Mosa.Runtime.Metadata.Signatures.SigType(Mosa.Runtime.Metadata.CilElementType.I4), GeneralPurposeRegister.EAX); RegisterOperand ecx = new RegisterOperand(new Mosa.Runtime.Metadata.Signatures.SigType(Mosa.Runtime.Metadata.CilElementType.I4), GeneralPurposeRegister.ECX); RegisterOperand reg = new RegisterOperand(new Mosa.Runtime.Metadata.Signatures.SigType(Mosa.Runtime.Metadata.CilElementType.I4), GeneralPurposeRegister.EBX); context.SetInstruction(CPUx86.Instruction.MovInstruction, eax, operand); context.AppendInstruction(CPUx86.Instruction.XorInstruction, ecx, ecx); context.AppendInstruction(CPUx86.Instruction.CpuIdEbxInstruction); context.AppendInstruction(CPUx86.Instruction.MovInstruction, result, reg); }
/// <summary> /// Replaces the instrinsic call site /// </summary> /// <param name="context">The context.</param> /// <param name="typeSystem">The type system.</param> public void ReplaceIntrinsicCall(Context context, ITypeSystem typeSystem) { Operand result = context.Result; SigType u4 = new SigType(CilElementType.U4); RegisterOperand eax = new RegisterOperand(u4, GeneralPurposeRegister.EAX); context.SetInstruction(CPUx86.Instruction.PopInstruction, eax); context.AppendInstruction(CPUx86.Instruction.AddInstruction, eax, new RegisterOperand(u4, GeneralPurposeRegister.ESP)); context.AppendInstruction(CPUx86.Instruction.MovInstruction, eax, new MemoryOperand(u4, GeneralPurposeRegister.EAX, new IntPtr(0))); context.AppendInstruction(CPUx86.Instruction.MovInstruction, result, eax); context.AppendInstruction(CPUx86.Instruction.PushInstruction, null, eax); }
/// <summary> /// Replaces the instrinsic call site /// </summary> /// <param name="context">The context.</param> /// <param name="typeSystem">The type system.</param> public void ReplaceIntrinsicCall(Context context, ITypeSystem typeSystem) { Operand result = context.Result; Operand operand1 = context.Operand1; RegisterOperand edx = new RegisterOperand(operand1.Type, GeneralPurposeRegister.EDX); RegisterOperand eax = new RegisterOperand(result.Type, GeneralPurposeRegister.EAX); context.SetInstruction(CPUx86.Instruction.MovInstruction, edx, operand1); context.AppendInstruction(CPUx86.Instruction.InInstruction, eax, edx); context.AppendInstruction(CPUx86.Instruction.MovInstruction, result, eax); }
/// <summary> /// Replaces the instrinsic call site /// </summary> /// <param name="context">The context.</param> /// <param name="typeSystem">The type system.</param> public void ReplaceIntrinsicCall(Context context, ITypeSystem typeSystem) { Operand dest = context.Operand1; Operand value = context.Operand2; RegisterOperand edx = new RegisterOperand(dest.Type, GeneralPurposeRegister.EDX); RegisterOperand eax = new RegisterOperand(value.Type, GeneralPurposeRegister.EAX); MemoryOperand memory = new MemoryOperand(new SigType(context.InvokeTarget.Signature.Parameters[1].Type), GeneralPurposeRegister.EDX, new IntPtr(0)); context.SetInstruction(CPUx86.Instruction.MovInstruction, edx, dest); context.AppendInstruction(CPUx86.Instruction.MovInstruction, eax, value); context.AppendInstruction(CPUx86.Instruction.MovInstruction, memory, eax); }
/// <summary> /// Replaces the instrinsic call site /// </summary> /// <param name="context">The context.</param> /// <param name="typeSystem">The type system.</param> public void ReplaceIntrinsicCall(Context context, ITypeSystem typeSystem) { SigType u4 = new SigType(Runtime.Metadata.CilElementType.U4); RegisterOperand ebp = new RegisterOperand(u4, GeneralPurposeRegister.EBP); RegisterOperand esp = new RegisterOperand(u4, GeneralPurposeRegister.ESP); RegisterOperand eax = new RegisterOperand(u4, GeneralPurposeRegister.EAX); RegisterOperand ebx = new RegisterOperand(u4, GeneralPurposeRegister.EBX); RegisterOperand ecx = new RegisterOperand(u4, GeneralPurposeRegister.ECX); RegisterOperand edx = new RegisterOperand(u4, GeneralPurposeRegister.EDX); RegisterOperand esi = new RegisterOperand(u4, GeneralPurposeRegister.ESI); RegisterOperand edi = new RegisterOperand(u4, GeneralPurposeRegister.EDI); context.SetInstruction(CPUx86.Instruction.PushInstruction, null, ebp); context.AppendInstruction(CPUx86.Instruction.MovInstruction, ebp, esp); context.AppendInstruction(CPUx86.Instruction.PushInstruction, null, ebx); context.AppendInstruction(CPUx86.Instruction.PushInstruction, null, esi); context.AppendInstruction(CPUx86.Instruction.PushInstruction, null, edi); // Load register context context.AppendInstruction(CPUx86.Instruction.MovInstruction, eax, new MemoryOperand(u4, GeneralPurposeRegister.ESP, new IntPtr(28))); // Load exception handler context.AppendInstruction(CPUx86.Instruction.MovInstruction, ecx, new MemoryOperand(u4, GeneralPurposeRegister.ESP, new IntPtr(32))); // Save EBP context.AppendInstruction(CPUx86.Instruction.PushInstruction, null, ebp); // Restore register values context.AppendInstruction(CPUx86.Instruction.MovInstruction, ebp, new MemoryOperand(u4, GeneralPurposeRegister.EAX, new IntPtr(24))); context.AppendInstruction(CPUx86.Instruction.MovInstruction, ebx, new MemoryOperand(u4, GeneralPurposeRegister.EAX, new IntPtr(4))); context.AppendInstruction(CPUx86.Instruction.MovInstruction, esi, new MemoryOperand(u4, GeneralPurposeRegister.EAX, new IntPtr(16))); context.AppendInstruction(CPUx86.Instruction.MovInstruction, edi, new MemoryOperand(u4, GeneralPurposeRegister.EAX, new IntPtr(20))); // Align ESP context.AppendInstruction(CPUx86.Instruction.MovInstruction, edx, esp); context.AppendInstruction(CPUx86.Instruction.AndInstruction, esp, new ConstantOperand(u4, 0xFFFFFFF0u)); context.AppendInstruction(CPUx86.Instruction.SubInstruction, esp, new ConstantOperand(u4, 0x8u)); // Save original ESP context.AppendInstruction(CPUx86.Instruction.PushInstruction, null, edx); // Call catch handler context.AppendInstruction(CPUx86.Instruction.CallInstruction, ecx); // Restore registers context.AppendInstruction(CPUx86.Instruction.PopInstruction, esp); context.AppendInstruction(CPUx86.Instruction.PopInstruction, ebp); context.AppendInstruction(CPUx86.Instruction.PopInstruction, esi); context.AppendInstruction(CPUx86.Instruction.PopInstruction, edi); context.AppendInstruction(CPUx86.Instruction.PopInstruction, ebx); context.AppendInstruction(CPUx86.Instruction.LeaveInstruction); context.AppendInstruction(CPUx86.Instruction.RetInstruction); }
/// <summary> /// Replaces the instrinsic call site /// </summary> /// <param name="context">The context.</param> /// <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)); }
/// <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() + "()")); }
/// <summary> /// Replaces the instrinsic call site /// </summary> /// <param name="context">The context.</param> public void ReplaceIntrinsicCall(Context context) { if (!(context.Operand1 is ConstantOperand)) throw new InvalidOperationException(); Operand result = context.Result; ControlRegister control; switch ((int)(context.Operand1 as ConstantOperand).Value) { case 0: control = ControlRegister.CR0; break; case 2: control = ControlRegister.CR2; break; case 3: control = ControlRegister.CR3; break; case 4: control = ControlRegister.CR4; break; default: throw new InvalidOperationException(); } RegisterOperand imm = new RegisterOperand(new SigType(CilElementType.U4), GeneralPurposeRegister.EAX); context.SetInstruction(IR.Instruction.MoveInstruction, imm, new RegisterOperand(new SigType(CilElementType.U4), control)); context.AppendInstruction(IR.Instruction.MoveInstruction, result, imm); }
/// <summary> /// Replaces the instrinsic call site /// </summary> /// <param name="context">The context.</param> /// <param name="typeSystem">The type system.</param> public void ReplaceIntrinsicCall(Context context, ITypeSystem typeSystem) { MemoryOperand operand = new MemoryOperand(new Mosa.Runtime.Metadata.Signatures.SigType(Mosa.Runtime.Metadata.CilElementType.Ptr), GeneralPurposeRegister.EAX, new System.IntPtr(0)); context.SetInstruction(CPUx86.Instruction.MovInstruction, new RegisterOperand(new Mosa.Runtime.Metadata.Signatures.SigType(Mosa.Runtime.Metadata.CilElementType.Ptr), GeneralPurposeRegister.EAX), context.Operand1); context.AppendInstruction(CPUx86.Instruction.LgdtInstruction, null, operand); RegisterOperand ax = new RegisterOperand(new Mosa.Runtime.Metadata.Signatures.SigType(Mosa.Runtime.Metadata.CilElementType.I2), GeneralPurposeRegister.EAX); RegisterOperand ds = new RegisterOperand(new Mosa.Runtime.Metadata.Signatures.SigType(Mosa.Runtime.Metadata.CilElementType.I2), SegmentRegister.DS); RegisterOperand es = new RegisterOperand(new Mosa.Runtime.Metadata.Signatures.SigType(Mosa.Runtime.Metadata.CilElementType.I2), SegmentRegister.ES); RegisterOperand fs = new RegisterOperand(new Mosa.Runtime.Metadata.Signatures.SigType(Mosa.Runtime.Metadata.CilElementType.I2), SegmentRegister.FS); RegisterOperand gs = new RegisterOperand(new Mosa.Runtime.Metadata.Signatures.SigType(Mosa.Runtime.Metadata.CilElementType.I2), SegmentRegister.GS); RegisterOperand ss = new RegisterOperand(new Mosa.Runtime.Metadata.Signatures.SigType(Mosa.Runtime.Metadata.CilElementType.I2), SegmentRegister.SS); context.AppendInstruction(CPUx86.Instruction.MovInstruction, ax, new ConstantOperand(new Mosa.Runtime.Metadata.Signatures.SigType(Mosa.Runtime.Metadata.CilElementType.I4), (int)0x00000010)); context.AppendInstruction(CPUx86.Instruction.MovInstruction, ds, ax); context.AppendInstruction(CPUx86.Instruction.MovInstruction, es, ax); context.AppendInstruction(CPUx86.Instruction.MovInstruction, fs, ax); context.AppendInstruction(CPUx86.Instruction.MovInstruction, gs, ax); context.AppendInstruction(CPUx86.Instruction.MovInstruction, ss, ax); context.AppendInstruction(CPUx86.Instruction.FarJmpInstruction); context.AppendInstruction(CPUx86.Instruction.NopInstruction); context.Previous.SetBranch(context.Offset); }
/// <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); }
/// <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); }